import os, sys
from time import time

from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget,
                             QGraphicsDropShadowEffect,
                             QFileDialog, QMessageBox,
                             QSystemTrayIcon, QMenu, QAction, QWidgetAction)
from PyQt5.QtCore import (Qt, QSize, QDir, QSharedMemory)
from PyQt5.QtGui import (QGuiApplication, QIcon, QPixmap)
import qtawesome as qta

from widgets import ui_PasteWindow

class MainWindow(QMainWindow):
    paste_windows = []
    paste_ids = []

    def __init__(self):
        QMainWindow.__init__(self)

        self.setup_tray()

    def setup_tray(self):
        color = 'black'
        action_paste = QAction(qta.icon('fa.file-o', color=color), '贴图', self)
        action_paste.triggered.connect(self.paste_)

        action_hide_showall = QAction(qta.icon('fa.eye', color=color), '显示所有贴图', self)
        action_hide_showall.triggered.connect(self.show_all)
        action_hide_hideall = QAction(qta.icon('fa.eye-slash', color=color), '隐藏所有贴图', self)
        action_hide_hideall.triggered.connect(self.hide_all)
        hide_menu = QMenu('显示/隐藏', self)
        hide_menu.addAction(action_hide_showall)
        hide_menu.addAction(action_hide_hideall)

        action_saveall = QAction(qta.icon('fa.floppy-o', color=color), '全部保存', self)
        action_saveall.triggered.connect(self.save_all)

        action_cache_paste = QAction(qta.icon('fa.file-o', 'fa.repeat', color=color, options=[{}, {'scale_factor': 0.6}]), '恢复缓存', self)
        action_cache_paste.triggered.connect(self.setup_caches)
        action_cache_clear = QAction(qta.icon('fa.trash-o', color=color), '清除缓存', self)
        action_cache_clear.triggered.connect(self.clear_caches)
        caches_menu = QMenu('缓存', self)
        caches_menu.addAction(action_cache_paste)
        caches_menu.addAction(action_cache_clear)

        action_quit = QAction(qta.icon('fa.power-off', color='#f33'), '退出', self)
        action_quit.triggered.connect(app.quit)

        self.tray_menu = QMenu(self)
        self.tray_menu.addAction(action_paste)
        self.tray_menu.addMenu(hide_menu)
        self.tray_menu.addSeparator()
        self.tray_menu.addAction(action_saveall)
        self.tray_menu.addMenu(caches_menu)
        self.tray_menu.addSeparator()
        self.tray_menu.addAction(action_quit)

        self.tray_icon = QSystemTrayIcon()
        self.tray_icon.setObjectName('tray_icon')
        self.tray_icon.setContextMenu(self.tray_menu)
        self.tray_icon.setIcon(QIcon('ico.ico'))
        self.tray_icon.setToolTip('Hi贴图')
        self.tray_icon.activated.connect(self.on_tray_activated)
        self.tray_icon.show()

    # 隐藏所有贴图
    def hide_all(self):
        for window in self.paste_windows:
            try:
                window.setVisible(False)
            except:
                pass

    # 显示所有贴图
    def show_all(self):
        for window in self.paste_windows:
            try:
                window.setVisible(True)
            except:
                pass

    # 全部保存
    def save_all(self):
        for window in self.paste_windows:
            try:
                window.save()
            except:
                pass

    # 恢复缓存
    def setup_caches(self):
        for file in os.listdir('cache/'):
            try:
                if int(file.split('_')[0]) not in self.paste_ids:
                    self.paste(int(file.split('_')[0]), f'cache/{file}')
            except:
                pass

    # 清除缓存
    def clear_caches(self):
        for file in os.listdir('cache/'):
            os.remove(f'cache/{file}')

    # 贴图
    def paste_(self):
        self.paste(int(time()))

    # 贴图
    def paste(self, id_, file=None):   
        self.paste_ids.append(id_)     
        self.paste_windows.append(PasteWindow(id_, file))

# ======== 自定义槽函数 ========

    def on_tray_activated(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.paste_()

class PasteWindow(QWidget):
    __is_moving = False
    __move_pos = None
    __is_resizing = False
    __last_pos = None

    __path = None
    id_ = 0

    __width = 0
    __height = 0

    __is_top = False

    def __init__(self, id_, file=None):
        QWidget.__init__(self)
        self.ui = ui_PasteWindow.Ui_Form()
        self.ui.setupUi(self)

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool) # 窗口去边框
        self.setAttribute(Qt.WA_DeleteOnClose)
        QApplication.setQuitOnLastWindowClosed(False)

        self.__path = file
        self.id_ = id_

        self.setup_shadow()
        self.setup_ui()
        self.setup_events()
        self.setup_menu()

        self.save()

    def setup_ui(self):
        if self.__path:
            x, y, width, height = list(map(int, self.__path.split('.')[0].split('_')[1:]))
            self.move(x, y)

            pixmap = QPixmap(self.__path)
            size = pixmap.size()
        else:
            pixmap = clipboard.pixmap()

            size = pixmap.size()
            width, height = size.width(), size.height()

        self.__width, self.__height = size.width(), size.height()

        self.ui.image.setPixmap(pixmap)

        self.show()

        self.setMinimumSize(0, 0)
        self.resize(width + 20, height + 20)

    def setup_events(self):
        self.ui.image.mouseDoubleClickEvent = self.on_image_mouseDoubleClickEvent
        self.ui.image.mousePressEvent = self.on_image_mousePressEvent
        self.ui.image.mouseMoveEvent = self.on_image_mouseMoveEvent
        self.ui.image.mouseReleaseEvent = self.on_image_mouseReleaseEvent
    
    # 设置窗口阴影
    def setup_shadow(self):
        self.effect_shadow = QGraphicsDropShadowEffect(self) # 创建阴影
        self.effect_shadow.setOffset(0, 0) # 偏移
        self.effect_shadow.setBlurRadius(10) # 阴影半径
        self.effect_shadow.setColor(Qt.black) # 阴影颜色

        self.setAttribute(Qt.WA_TranslucentBackground)   #将窗口设置为透明
        self.setGraphicsEffect(self.effect_shadow) # 将设置套用到窗口中

    def setup_menu(self):
        color = 'black'
        self.right_menu = QMenu(self)
        action_initsize = QAction(qta.icon('fa.window-maximize', color=color), '初始大小', self)
        action_initsize.triggered.connect(self.initsize)
        action_hide = QAction(qta.icon('fa.eye-slash', color=color), '隐藏', self)
        action_hide.triggered.connect(self.hide)
        action_cut = QAction(qta.icon('fa.scissors', color=color), '剪切', self)
        action_cut.triggered.connect(self.cut)
        action_copy = QAction(qta.icon('fa.clone', color=color), '复制', self)
        action_copy.triggered.connect(self.copy)
        action_save = QAction(qta.icon('fa.floppy-o', color=color), '保存', self)
        action_save.triggered.connect(self.save)
        action_save_as = QAction(qta.icon('fa.share-square-o', color=color), '另存为', self)
        action_save_as.triggered.connect(self.save_as)
        action_del = QAction(qta.icon('fa.trash-o', color=color), '删除', self)
        action_del.triggered.connect(self.delete)

        self.right_menu.addAction(action_initsize)
        self.right_menu.addAction(action_hide)
        self.right_menu.addSeparator()
        self.right_menu.addAction(action_cut)
        self.right_menu.addAction(action_copy)
        self.right_menu.addSeparator()
        self.right_menu.addAction(action_save)
        self.right_menu.addAction(action_save_as)
        self.right_menu.addAction(action_del)

# ========== 事件 ==========

    def on_image_mouseDoubleClickEvent(self, event):
        self.delete()

    # image 按下
    def on_image_mousePressEvent(self, event):
        self.__is_moving = True # 正在拖动
        self.__move_pos = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置

        if event.button() == Qt.LeftButton:
            self.__is_resizing = (event.x() > self.ui.image.width() - 10) and (event.y() > self.ui.image.height() - 10)
            self.__last_pos = event.pos()

    # image 拖动
    def on_image_mouseMoveEvent(self, event):        
        # 正在调整则改变窗口大小，否则设置光标样式
        if self.__is_resizing:
            width = self.__width + 20
            height = self.__height + 20

            w = (event.x() + 20) / width
            h = (event.y() + 20) / height

            distance = min(w, h)

            # 改变大小
            new_width = int(width * distance)
            new_height = int(height * distance)

            if new_width < 30 or new_height < 30:
                return

            self.setMinimumSize(0, 0)

            self.resize(new_width, new_height)

            return

        else:
            is_right = event.x() > self.ui.image.width() - 10
            is_bottom = event.y() > self.ui.image.height() - 10

            # 光标样式
            if is_right and is_bottom: # 右下角
                cursor = Qt.SizeFDiagCursor
            else:
                cursor = Qt.ArrowCursor 

            self.ui.image.setCursor(cursor)

        if self.__is_moving:
            self.move(event.globalPos() - self.__move_pos) # 更改窗口位置
    
    # image 松开
    def on_image_mouseReleaseEvent(self, event):
        if self.__is_moving:
            self.__is_moving = False # 结束
            self.save()

        if event.button() == Qt.RightButton:
            self.right_menu.exec_(event.globalPos())

        self.__is_resizing = False
        self.ui.image.setCursor(Qt.ArrowCursor)

# ========== 其他方法 ==========

    # 恢复初始大小
    def initsize(self):
        self.resize(self.__width + 20, self.__height + 20)

    # 隐藏
    def hide(self):
        self.setVisible(False)

    # 剪切
    def cut(self):
        self.copy()
        self.delete()

    # 复制
    def copy(self):
        clipboard.setPixmap(self.ui.image.pixmap())

    # 保存
    def save(self):
        try:
            os.remove(self.__path)
        except:
            pass

        id_ = self.id_
        x, y = self.x(), self.y()
        width, height = self.ui.image.width(), self.ui.image.height()

        self.__path = f'cache/{id_}_{x}_{y}_{width}_{height}.png'
        self.ui.image.pixmap().save(self.__path)

    # 另存为
    def save_as(self):
        cur_path = QDir.currentPath()
        title = '另存为'
        filt = '所有文件(*.*);;PNG图片文件(*.png)'
        init_filt = 'PNG图片文件(*.png)'

        path, filt = QFileDialog.getSaveFileName(self, title, cur_path, filt, init_filt)

        try:
            self.ui.image.pixmap().save(path)
        except:
            QMessageBox.warning(self, '保存失败', '保存失败，请重试。')

    # 删除
    def delete(self):
        self.close()
        os.remove(self.__path)

def is_memory_attach(key):
    global share
    
    share = QSharedMemory()
    share.setKey(key)

    if share.attach():
        QMessageBox.warning(None, '程序已在运行', '程序已在运行，请关闭后重试。')
        return True
    else:
        share.create(1)
        return False

def main():
    global app, clipboard, window

    app = QApplication([])
    clipboard = QGuiApplication.clipboard()

    if is_memory_attach('HiPaste'):
        return
    
    window = MainWindow()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()